import React, { Component } from 'react';
import { Input, Tree, Switch, message } from 'antd';
import { PlusOutlined, EllipsisOutlined } from '@ant-design/icons';
import styles from './LeftNav.module.less';
import { GlobalRulesConfig, Group, GroupChild } from '../../configs/baseConfig';
import { ChromeUtil, ByteUtil } from '../../utils';

export class LeftNav extends Component {

  state = {
    collectionData: GlobalRulesConfig.groupRules || [],
    treeExpandedKeys: [],
    selectedNode: null,
    popoverTop: 0,
    isShowActionPop: false,
    actionData: null,
    renameKey: null,
    isGlobalOpen: GlobalRulesConfig.isGlobalOpen,
    uploadKey: null,
    memory: null
  }

  constructor(props) {
    super(props);
  }

  componentDidMount() {
    if (!this.state.treeExpandedKeys.length && this.state.collectionData.length) {
      this.switchFirstSelected();
    }
  }

  switchFirstSelected(collections) {
    collections = collections || this.state.collectionData;
    if (!collections.length) {
      return;
    }
    let { key, children } = collections[0];
    let selectedNode = children[0];
    if (GlobalRulesConfig.selectedNode && GlobalRulesConfig.selectedNode.parentKey) {
      key = GlobalRulesConfig.selectedNode.parentKey;
      selectedNode = GlobalRulesConfig.selectedNode;
    }
    const treeExpandedKeys = this.state.treeExpandedKeys || [];
    if (!treeExpandedKeys.includes(key)) {
      treeExpandedKeys.push(key);
    }
    this.setState({ treeExpandedKeys: treeExpandedKeys.flat() });
    this.treeItemClick(null, selectedNode);
  }

  /**
   * 获取空条目
   * @param {父元素key} parentKey string
   */
  getNullRecord = (parentKey) => {
    if (!parentKey) {
      return new Group();
    }
    return new GroupChild(parentKey);
  }

  updateConfig = (data) => {
    if (!data) {
      return;
    }
    this.setState({
      memory: ByteUtil.stringToByte(JSON.stringify(this.state.collectionData))
    });
    ChromeUtil.storageLocalSet(data);
    ChromeUtil.sendRuntimeMsg({ to: 'background', type: 'updateConfig', data });
  }

  addCollection = (e) => {
    const collections = [...this.state.collectionData];
    collections.push(this.getNullRecord());
    this.setState({ collectionData: collections });
    this.updateConfig({ groupRules: collections });
  }

  switchChange = (e) => {
    const isGlobalOpen = !GlobalRulesConfig.isGlobalOpen;
    GlobalRulesConfig.isGlobalOpen = isGlobalOpen;
    this.setState({ isGlobalOpen });
    this.updateConfig({ isGlobalOpen });
  }

  treeExpand = (expandedKeys) => {
    this.setState({ treeExpandedKeys: expandedKeys });
  }

  expandTree = (currentKey) => {
    if (!currentKey) {
      return;
    }
    const treeExpandedKeys = this.state.treeExpandedKeys;
    if (!treeExpandedKeys.includes(currentKey)) {
      treeExpandedKeys.push(currentKey);
      this.setState({ treeExpandedKeys: treeExpandedKeys.flat() });
    }
  }

  treeItemClick = (e, nodeData) => {
    e && e.stopPropagation();
    if (!nodeData || nodeData.children) {
      return;
    }
    const selectedNode = { ...nodeData, request: { ...nodeData.request } };
    this.setState({ selectedNode });
    ChromeUtil.storageLocalSet({ selectedNode });
    const parentNode = this.state.collectionData.find(item => item.key === nodeData.parentKey);
    if (!parentNode) {
      return;
    }
    if (typeof this.props.updateRequest === 'function') {
      this.props.updateRequest({
        currentNode: selectedNode,
        breadCrumb: [
          {
            title: parentNode.title,
            key: parentNode.key
          }, {
            title: selectedNode.title,
            key: selectedNode.key
          }
        ]
      });
    }
  }

  updateNode = (node) => {
    let collections = [...this.state.collectionData];
    const parentNode = collections.find(item => item.key === node.parentKey);
    if (!parentNode) {
      return;
    }
    ChromeUtil.storageLocalSet({ selectedNode: node });
    const index = parentNode.children.findIndex(item => item.key === node.key);
    parentNode.children.splice(index, 1, node);
    this.setState({ collectionData: collections });
    this.updateConfig({ groupRules: collections });
  }

  ellipsisClick = (e, actionData) => {
    e.stopPropagation();
    this.setState({ popoverTop: e.clientY + 'px', actionData, isShowActionPop: true });
  }

  downloadConfig = (jsonData, fileName) => {
    const aTmp = document.createElement('a');
    aTmp.download = fileName + '.json';
    aTmp.style.display = 'none';
    const blob = new Blob([jsonData]);
    const objectUrl = URL.createObjectURL(blob);
    aTmp.href = objectUrl;
    aTmp.click();
    window.URL.revokeObjectURL(objectUrl);
  };

  fileInputChange = (e) => {
    const files = e.target.files;
    const reader = new FileReader();
    reader.readAsText(files[0], 'utf-8');
    reader.onload = (result) => {
      try {
        const collections = [...this.state.collectionData];
        const uploadData = JSON.parse(result.target.result);
        let uploadChildren = Array.isArray(uploadData.children) ? uploadData.children : [uploadData];
        uploadChildren = uploadChildren.filter(item => item.request).map(item => {
          const result = this.getNullRecord(this.state.uploadKey);
          result.title = item.title;
          result.request = item.request;
          return result;
        });
        const uploadCollection = collections.find(item => item.key === this.state.uploadKey);
        if (uploadCollection) {
          uploadCollection.children = uploadCollection.children.concat(uploadChildren);
          this.setState({ collectionData: collections, uploadKey: '' });
          this.updateConfig({ groupRules: collections });
        }
      } catch (error) {
        message.error('导入失败' + error.message);
      }
      this.fileRef.value = '';
    }
  }

  actionItemClick = (e, type) => {
    e && e.stopPropagation();
    this.setState({ isShowActionPop: false });

    const actionData = this.state.actionData;
    const currentKey = actionData.key;

    if (type === 'rename') {
      this.setState({ renameKey: currentKey });
      return;
    }
    if (type === 'export') {
      this.downloadConfig(JSON.stringify(actionData), actionData.title);
      return;
    }
    if (type === 'import' && this.fileRef) {
      this.setState({ uploadKey: this.state.actionData.key });
      this.fileRef.click();
      return;
    }

    let collections = [...this.state.collectionData];
    let treeExpandedKeys = [...this.state.treeExpandedKeys];

    if (type === 'add') {
      const child = this.getNullRecord(currentKey);
      actionData.children.unshift(child);
      if (!treeExpandedKeys.includes(currentKey)) {
        treeExpandedKeys.push(currentKey);
      }
      this.setState({ treeExpandedKeys });
      this.treeItemClick(null, child);
    } else if (type === 'delete') {
      if (this.state.selectedNode && [this.state.selectedNode.parentKey, this.state.selectedNode.key].includes(currentKey)) {
        if (typeof this.props.updateRequest === 'function') {
          this.setState({ selectedNode: null });
          ChromeUtil.storageLocalSet({ selectedNode: null });
          this.props.updateRequest({
            breadCrumb: []
          });
        }
      }
      if (!actionData.parentKey) {
        collections = collections.filter(item => item.key !== currentKey);
        // if (this.state.selectedNode.parentKey === currentKey) {
        //   this.switchFirstSelected(collections);
        // }
      } else {
        const actionParent = collections.find(item => item.key === actionData.parentKey);
        if (actionParent) {
          actionParent.children = actionParent.children.filter(item => item.key !== currentKey);
        }
      }
      treeExpandedKeys = treeExpandedKeys.filter(item => item.key !== currentKey);
    }
    this.setState({ collectionData: collections, treeExpandedKeys });
    this.updateConfig({ groupRules: collections });
  }

  renameBlur = (e) => {
    let collections = [...this.state.collectionData];
    const actionData = this.state.actionData;
    const isUpdateBreadCrumb = this.state.selectedNode && (this.state.selectedNode.parentKey === actionData.key ||
      this.state.selectedNode.key === actionData.key);
    const renameResult = e.target.value;
    if (!actionData.parentKey) {
      const currentAction = collections.find(item => item.key === actionData.key);
      currentAction.title = renameResult;
    } else {
      const actionParent = collections.find(item => item.key === actionData.parentKey);
      if (actionParent) {
        const renameItem = actionParent.children.find(item => item.key === actionData.key);
        renameItem.title = renameResult;
      }
    }
    this.setState({ collectionData: collections, renameKey: '', actionData: null },
      () => {
        if (isUpdateBreadCrumb) {
          const selectedNode = { ...this.state.selectedNode };
          selectedNode.title = !actionData.parentKey ? selectedNode.title : renameResult;
          this.treeItemClick(null, selectedNode);
        }
      });
    this.updateConfig({ groupRules: collections });
  }

  popoverLeft = (e) => {
    if (!this.state.renameKey) {
      this.setState({ isShowActionPop: false, actionData: null });
    }
  }

  render() {
    return (
      <>
        <header className={styles.actionHeader}>
          <div className={styles.iconContent}>
            <span className={styles.iconItem} title='添加群组' onClick={this.addCollection}>
              <PlusOutlined style={{
                fontSize: '14px',
              }} />
            </span>
          </div>
          <div>
            <Switch
              style={{ zIndex: 10 }}
              checkedChildren="开启"
              unCheckedChildren="关闭"
              defaultChecked={this.state.isGlobalOpen}
              onChange={this.switchChange}
            />
          </div>
        </header>
        <div className={styles.memory}>已用容量：<span className={styles.used}>{this.state.memory} / 5MB</span></div>
        <div className={styles.treeContent}>
          <Tree
            onExpand={this.treeExpand}
            expandedKeys={this.state.treeExpandedKeys}
            treeData={this.state.collectionData}
            titleRender={(nodeData) => {
              return (
                <>
                  <div className={styles.treeMenu} onClick={(e) => this.treeItemClick(e, nodeData)}>
                    <div className={styles.treeName} style={{ background: this.state.selectedNode && this.state.selectedNode.key === nodeData.key && !nodeData.children ? '#ededed' : '' }}>
                      {this.state.renameKey === nodeData.key ? <div className={styles.renameInput}>
                        <Input
                          placeholder={'请输入名称'}
                          bordered={false}
                          size='small'
                          autoFocus={true}
                          onBlur={e => this.renameBlur(e)}
                          defaultValue={nodeData.title}
                          onClick={e => e.stopPropagation()}
                        />
                      </div> : (nodeData.request ? (<>
                        <span className={nodeData.request.isOpen && this.state.isGlobalOpen ? styles.method : styles.noLimit}>
                          {nodeData.request.method}
                        </span> {nodeData.title}</>) : nodeData.title)}
                    </div>
                    <div className={styles.ellipsisIcon} onClick={e => this.ellipsisClick(e, nodeData)}>
                      <EllipsisOutlined />
                    </div>
                  </div>
                  <div className={styles.actionPopover}
                    onMouseLeave={this.popoverLeft}
                    style={{ display: this.state.isShowActionPop ? 'block' : 'none', left: '100px', top: this.state.popoverTop }}>
                    <div className={styles.popoverContent}>
                      {
                        [{ type: 'add', name: '添加请求' },
                        { type: 'rename', name: '重命名' },
                        { type: 'export', name: '导出' },
                        { type: 'import', name: '导入' },
                        { type: 'delete', name: '删除' }].map(item => {
                          if (this.state.actionData) {
                            if (['add', 'import'].includes(item.type) && this.state.actionData.parentKey ||
                              item.type === 'delete' && this.state.collectionData.length === 1 && this.state.actionData.children) {
                              return ''
                            }
                          }
                          return <div onClick={e => this.actionItemClick(e, item.type)} className={styles.actionItem}>{item.name}</div>
                        })
                      }
                    </div>
                  </div>
                </>
              );
            }}
          />
        </div>
        <input className={styles.uploadInput} ref={ref => this.fileRef = ref} type="file"
          onChange={this.fileInputChange} />
      </>
    );
  }
}